/** 
 * \file store.h
 *
 * \description
 * Definições de uma estrutura e respectivas funções auxiliares
 *  para preservar o resultado de uma alocação
 */

# ifndef STORAGE_DEFINITION
# define STORAGE_DEFINITION

# define CUTTED_EDGE -1 // tem k ser negativo!

// CONFIGURAÇÔES
# define CONFIG_INITIAL_MODE "initial-distribuition-mode" // 0 nao limitar - 1 limitar e n alocar - 2 limiter e realocar
# define CONFIG_EXTRA_ORDER "add-extra-curricular-at-start"
# define CONFIG_BEST_METHOD "favorecer-melhores"

# include "../../util/hashs/chainingHashMap.h"
# include "../../util/lists/array-list.h"
# include "../../util/lists/linked-list.h"
# include "../../util/lists/queue.h"
# include "../uce/uce.h"
# include "../student/student.h"
# include "../../util/graphs/graph.h"
# include "../../io/files/uces/parser.h"
# include "../../io/files/students/parser.h"
# include "variables.h"

typedef struct {
        ArrayList **uces; // Guarda os alunos de cada UCE
        Graph *commonStudents; // Os valores das arestas vão representar o número de estudantes em comum
        char **mapUCEs; // Mapeamento da UCE em números!
        Graph *allocationGraph; // Grafo de alocações
        int nUCEs; // número de UCEs (da sempre jeito)
        LinkedList *nonAllocatedStudents; // Alunos não alocados!
        LinkedList *unhappyStudents;
        UCE **uceInfo;
        ArrayList *studentList;
} Store;


// FUNÇÔES


/**
 * \brief aloca espaço em memória para esta estrutura
 */
Store * newStore ();
/**
 * \brief Liberta da memória as estruturas usadas
 */
void freeStore (Store *st);
/**
 * \brief Remove uma aresta (unicamente sem testes)
 * \param st store
 * \param uceA indice A
 * \param uceB indice B
 */
void removeEdge (Store *st, int uceA, int uceB);
/**
 * \brief verifica se a UCE foi removida
 * \param st store
 * \param uceA indice A
 * \param uceB indice B
 * \return 1 se ja foi removida 0 se não
 */
int isRemovedEdge (Store *st, int uceA, int uceB);
/**
 * \brief Da o indice da uce
 * \param st store
 * \param uce UCE
 * \return indice ou -1
 */
int getUCEIndice (Store *st, char *uce);
/**
 * \brief Verifica se a uce Existe
 * \param st store
 * \param uce indice da UCE
 * \return 1 se existe 0 se nao
 */
int uceExists (Store *st, char *uce);
/**
 * \brief Adiciona aluno à lista de não alocados
 * \param store Store
 * \param st estudante
 */
void addNonAllocated (Store *store, Student *st);
/**
 * \brief Adiciona a informação proveniente da origem
 * \param st store
 * \param uces Mapa de UCEs
 * \param studentLIst lista de alunos
 */
void fillInfo (Store *st, ChainingHashMap *uces, ArrayList *studentList);
/**
 * \brief Da a diferença entre o número máximo de alunos e os alunos alocados.
 * \param st Store
 * \param uce Indice da UCE
 */
int getUCEgap (Store *st, int uce);

/**
 * \brief Adiciona uma aluno a uma UCE
 * \param store store
 * \param st Aluno
 * \param uce Indice da UCE
 * \param verifyHappyness 1 se se quiser adicionar à lista de tristes.
 * \param addToIfNotAllocated 1 se se quiser adicionar à lista de nao alocados se não se adicionar
 * \description
 * Esta função verifica se o aluno está na lista de nao alocados removendo-o caso a adição ocorra com sucesso!
 */
int addStudentToUCE (Store *store, Student *st, int uce, int verifyHappyness, int addToIfnotAllocated, int judgeLimits);

/**
 * \brief Remove aluno da UCE
 * \param store Store
 * \param st Aluno
 * \param uce UCE
 * \description
 *
 * Esta função verifica se o aluno está na lista de tristes removendo-o dessa lista!
 */
int removeStudentFromUCE (Store *store, Student *st, int uce);
/**
 * \brief Adiciona o aluno à sua uce percorrendo para isso a sua lista de preferencias (por ordem decrescente de preferencia)
 * \param st store
 * \param s aluno
 * \param recursive se se quer percorrer a lista toda 1 ou 0 se só se quer tentar a primeira preferência
 * \param addToNonAllocated adiciona à lista de nao alocados
 * \param limites verificar limites
 * \return 0 se nao conseguir 1 se sucesso!
 * \description
 * Esta função em caso do aluno querer participar em 2 uces adiciona os parametros à ligação (peso e contagem de alunos comuns)
 */
int addStudent (Store *st, Student *s, int recursive, int addToNonAllocated, int limites);
/**
 * \brief Remove o aluno da(s) uce(s) que está alocado
 * \param st Store
 * \param s Aluno
 * \description
 * Caso tenha 2 uces garante o bom funcionamento em colaboração com a função addStudent
 */
int removeStudent (Store *st, Student *s);
/**
 * \brief Distribui os aluno inicialmente pelas UCEs
 * \param st Store
 * \param pro Conta com os profissionais
 * \param extra Conta com os extra
 * \param mode Tipo de distribuição
 * \description
 * Tipo de distribuição:
 * 0 - Adiciona sempre à primeira preferência (sem contar com os limites)
 * 1 - Adiciona e verifica a capacidade da UCE - tenta só adicionar à(s) preferida(s) (se não adicionar vai para a lista de alunos não alocados)
 * 2 - Adiciona e verifica a capacidade da UCE - tenta adicionar em todas as combinações possiveis (por ordem de preferência) - se no fim não adicionar vai para a lista de não alocados
 */
void initialDistribuition (Store *st, int pro, int extra, int mode);

/**
 * \brief retira do store o grafico a colorar!
 */
Graph * getGraph (Store *st);

/**
 * \brief Aloca todos os estudantes de um tipo segundo o modo
 * \param st store
 * \param type tipo de aluno
 * \param mode modo
 * \description
 * 0 - Adiciona sempre à primeira preferência (sem contar com os limites)
 * 1 - Adiciona e verifica a capacidade da UCE - tenta só adicionar à(s) preferida(s) (se não adicionar vai para a lista de alunos não alocados)
 * 2 - Adiciona e verifica a capacidade da UCE - tenta adicionar em todas as combinações possiveis.
 */
void allocateRole (Store *st, StudentType type, int mode);

/**
 * \brief Remove a pior aresta
 * \param st Store
 * \return 0 se não houver arestas a remover | 1 se remover
 * \description
 * Tem o cuidado de remover os alunos em sobreposição e adiciona-os à lista de não alocados.
 */
int removeWorstEdge (Store *st);
/**
 * \brief Tenta alocar gente que não está contente a situações mais favoraveis
 * \description
 * Depois de remover uma aresta.. é possivel que alguns alunos vejam as suas preferências concretizadas
 */
void tryToMakeSomeoneHappy (Store *st);
/**
 * \brief Tenta alocar os alunos que ainda não estão alocados
 * \description
 * Depois de remover arestas é possivel que alunos que não estejam alocados
 * passem a estar alocados
 */
void tryToAllocateNonAllocated (Store *st);

# endif
